home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 039a / mawk10.zip / ARRAY.C < prev    next >
C/C++ Source or Header  |  1991-10-05  |  9KB  |  361 lines

  1.  
  2. /********************************************
  3. array.c
  4. copyright 1991, Michael D. Brennan
  5.  
  6. This is a source file for mawk, an implementation of
  7. the AWK programming language.
  8.  
  9. Mawk is distributed without warranty under the terms of
  10. the GNU General Public License, version 2, 1991.
  11. ********************************************/
  12.  
  13. /* $Log:    array.c,v $
  14.  * Revision 3.3.1.1  91/09/14  17:22:35  brennan
  15.  * VERSION 1.0
  16.  * 
  17.  * Revision 3.3  91/08/13  06:50:44  brennan
  18.  * VERSION .9994
  19.  * 
  20.  * Revision 3.2  91/06/28  04:16:00  brennan
  21.  * VERSION 0.999
  22.  * 
  23.  * Revision 3.1  91/06/07  10:26:48  brennan
  24.  * VERSION 0.995
  25.  * 
  26.  * Revision 2.3  91/05/22  07:39:40  brennan
  27.  * static prototypes
  28.  * 
  29.  * Revision 2.2  91/05/15  12:07:27  brennan
  30.  * dval hash table for arrays
  31.  * 
  32.  * Revision 2.1  91/04/08  08:22:15  brennan
  33.  * VERSION 0.97
  34.  * 
  35. */
  36.  
  37. #include "mawk.h"
  38. #include "symtype.h"
  39. #include "memory.h"
  40. #include "bi_vars.h"
  41.  
  42. /* convert doubles to string for array indexing */
  43. #define   A_FMT         "%.6g"
  44.  
  45. static ANODE *PROTO(find_by_sval, (ARRAY, STRING *, int) ) ;
  46. static D_ANODE *PROTO(find_by_dval, (ARRAY, double , int) ) ;
  47.  
  48. extern int returning ; 
  49.    /* flag -- on if returning from function call */
  50.  
  51. extern unsigned hash() ;
  52.  
  53. /* An array A is a pointer to an array of struct array,
  54.    which is two hash tables in one.  One for strings
  55.    and one for doubles.
  56.  
  57.    each array is of size A_HASH_PRIME.
  58.  
  59.    When an index is deleted via  delete A[i], the
  60.    ANODE is not removed from the hash chain.  A[i].cp
  61.    and A[i].sval are both freed and sval is set NULL.
  62.    This method of deletion simplifies for( i in A ) loops.
  63.  
  64.    On the D_ANODE list, we use real deletion and move to the
  65.    front on access.
  66.  
  67.    Separate nodes (as opposed to one type of node on two lists)
  68.    to
  69.      (1) d1 != d2, but sprintf(A_FMT,d1) == sprintf(A_FMT,d1)
  70.          so two dnodes can point at the same anode.
  71.      (2) Save a little data space(64K PC mentality).
  72.  
  73.    the cost is an extra level of indirection.
  74.  
  75.    Some care is needed so that things like
  76.      A[1] = 2 ; delete A["1"] work .
  77. */
  78.  
  79. #define  _dhash(d)    (((int)(d)&0x7fff)%A_HASH_PRIME)
  80. #define  DHASH(d)     (last_dhash=_dhash(d))
  81. static  unsigned  last_dhash ;
  82.  
  83.  
  84. static  ANODE *find_by_sval(A, sval, cflag)
  85.   ARRAY  A ;
  86.   STRING *sval ;
  87.   int  cflag ; /* create if on */
  88.    char *s = sval->str ;
  89.    unsigned h = hash(s) % A_HASH_PRIME ;
  90.    register ANODE *p = A[h].link ;
  91.    ANODE *q = 0 ; /* holds first deleted ANODE */
  92.  
  93.    while ( p )
  94.    {
  95.      if ( p->sval )
  96.      { if ( strcmp(s,p->sval->str) == 0 )  return p ; }
  97.      else /* its deleted, mark with q */
  98.      if ( ! q )  q = p ;  
  99.  
  100.      p = p->link ;
  101.    }
  102.  
  103.    /* not there */
  104.    if ( cflag )
  105.    {
  106.        if ( q )  p = q ; /* reuse the deleted node q */
  107.        else
  108.        { p = (ANODE *)zmalloc(sizeof(ANODE)) ;
  109.          p->link = A[h].link ; A[h].link = p ;
  110.        }
  111.  
  112.        p->sval = sval ;
  113.        sval->ref_cnt++ ;
  114.        p->cp = (CELL *) zmalloc(sizeof(CELL)) ;
  115.        p->cp->type = C_NOINIT ;
  116.    }
  117.    return p ;
  118. }
  119.  
  120.  
  121. /* on the D_ANODE list, when we find a node we move it
  122.    to the front of the hash chain */
  123.  
  124. static D_ANODE  *find_by_dval(A, d, cflag)
  125.   ARRAY  A ;
  126.   double d ;
  127.   int cflag ;
  128. {
  129.   unsigned h = DHASH(d) ;
  130.   register D_ANODE *p = A[h].dlink ;
  131.   D_ANODE *q = 0 ; /* trails p for move to front */
  132.   ANODE *ap ;
  133.  
  134.    while ( p )
  135.        if ( p->dval == d )
  136.        { /* found */
  137.          if ( ! p->ap->sval ) /* but it was deleted by string */
  138.          { if ( q )  q->dlink = p->dlink ;
  139.            else A[h].dlink = p->dlink ;
  140.            zfree(p, sizeof(D_ANODE)) ;
  141.            break ; 
  142.          }
  143.          /* found */
  144.          if ( !q )  return  p ; /* already at front */
  145.          else /* delete to put at front */
  146.          { q->dlink = p->dlink ; goto found ; }
  147.        }
  148.        else
  149.        { q = p ; p = p->dlink ; }
  150.  
  151.    /* not there, still need to look by sval 
  152.       CANNOT use temp_buff, may be in use by split */
  153.    
  154.    { char xbuff[16] ;
  155.      STRING *sval ;
  156.  
  157.      (void) sprintf(xbuff, A_FMT, d) ;
  158.      sval = new_STRING(xbuff) ;
  159.      ap = find_by_sval(A, sval, cflag) ;
  160.      free_STRING(sval) ;
  161.    }    
  162.  
  163.    if ( ! ap )  return (D_ANODE *) 0 ;
  164.    /* create new D_ANODE  */
  165.    p = (D_ANODE *) zmalloc(sizeof(D_ANODE)) ;
  166.    p->ap = ap ; p->dval = d ;
  167.  
  168. found : /* put p at front */
  169.    p->dlink = A[h].dlink ; A[h].dlink = p ;
  170.    return p ;
  171. }
  172.  
  173. CELL *array_find(A, cp, create_flag)
  174.   ARRAY A ;
  175.   CELL *cp ;
  176.   int create_flag ;
  177. {
  178.   ANODE *ap ;
  179.   D_ANODE *dp ;
  180.  
  181.   switch( cp->type )
  182.   {
  183.     case C_DOUBLE :
  184.         return  (dp = find_by_dval(A, cp->dval, create_flag))
  185.                 ? dp->ap->cp : (CELL *) 0 ;
  186.  
  187.     case  C_NOINIT :
  188.         ap = find_by_sval(A, &null_str, create_flag) ;
  189.         break ;
  190.  
  191.     default :
  192.         ap = find_by_sval(A, string(cp), create_flag) ;
  193.         break ;
  194.   }
  195.  
  196.   return  ap ? ap->cp : (CELL *) 0 ;
  197. }
  198.  
  199.  
  200. void  array_delete(A, cp)
  201.   ARRAY A ; CELL *cp ;
  202. {
  203.   ANODE *ap ;
  204.   D_ANODE *dp ;
  205.  
  206.   switch( cp->type )
  207.   {
  208.     case C_DOUBLE :
  209.         if ( !(dp = find_by_dval(A, cp->dval, 0)) ) return ;
  210.  
  211.         ap = dp->ap ;
  212.         /* dp is at front of A[last_dhash], delete the D_ANODE */
  213.         A[last_dhash].dlink = dp->dlink ;
  214.         zfree(dp, sizeof(D_ANODE)) ;
  215.         break ;
  216.  
  217.     case  C_NOINIT :
  218.         ap = find_by_sval(A, &null_str, 0) ;
  219.         break ;
  220.  
  221.     default :
  222.         ap = find_by_sval(A, string(cp), 0) ;
  223.         break ;
  224.   }
  225.  
  226.   if ( ap )
  227.   { free_STRING(ap->sval) ; ap->sval = (STRING *) 0 ;
  228.     cell_destroy(ap->cp)  ; zfree(ap->cp, sizeof(CELL)) ;
  229.   }
  230. }
  231.  
  232.  
  233.  
  234. /* for ( i in A ) ,
  235.    loop over elements of an array 
  236.  
  237. sp[0].ptr :  a pointer to A ( the hash table of A)
  238. sp[-1] :  a pointer to i ( a cell ptr)
  239.  
  240. cdp[0] :  a stop op to catch breaks
  241. cdp[1] :  offset from cdp of the code after the loop (n+2)
  242. cdp[2] :  start of body of the loop
  243. cdp[3..n] : the rest of the body
  244. cdp[n+1]  : a stop op to delimit the body and catch continues
  245. */
  246.  
  247. INST  *array_loop( cdp, sp, fp) /* passed code, stack and frame ptrs */
  248.   INST *cdp ; 
  249.   CELL *sp, *fp ;
  250. { int i ;
  251.   register ANODE *p ;
  252.   ARRAY   A = (ARRAY) sp-- -> ptr ;
  253.   register CELL *cp = (CELL *) sp-- -> ptr ;
  254.  
  255.   for ( i = 0 ; i < A_HASH_PRIME ; i++ )
  256.   for ( p = A[i].link ; p ; p = p->link )
  257.   { if ( ! p->sval /* its deleted */ )  continue ;
  258.   
  259.     cell_destroy(cp) ;
  260.     cp->type = C_STRING ;
  261.     cp->ptr = (PTR) p->sval ;
  262.     p->sval->ref_cnt++ ;
  263.  
  264.     /* execute the body of the loop */
  265.     if ( execute(cdp+2, sp, fp) == cdp /* exec'ed a break statement */
  266.          || returning  /* function return in body of loop */
  267.        )  
  268.            goto break2 /* break both for loops */ ; 
  269.   }
  270.  
  271. break2 :
  272.   return   cdp + cdp[1].op ;
  273. }
  274.  
  275.  
  276. /* cat together cnt elements on the eval stack to form
  277.    an array index using SUBSEP */
  278.  
  279. CELL *array_cat( sp, cnt)
  280.   register CELL *sp ;
  281.   int cnt ;
  282. { register CELL *p ;  /* walks the stack */
  283.   CELL subsep ;  /* a copy of bi_vars[SUBSEP] */
  284.   unsigned subsep_len ;
  285.   char *subsep_str ;
  286.   unsigned total_len ; /* length of cat'ed expression */
  287.   CELL *top ;  /* sp at entry */
  288.   char *t ; /* target ptr when catting */
  289.   STRING *sval ;  /* build new STRING here */
  290.  
  291.   /* get a copy of subsep, we may need to cast */
  292.   (void) cellcpy(&subsep, bi_vars + SUBSEP) ;
  293.   if ( subsep.type < C_STRING ) cast1_to_s(&subsep) ;
  294.   subsep_len = string(&subsep)->len ;
  295.   subsep_str = string(&subsep)->str ;
  296.   total_len = --cnt * subsep_len ;
  297.  
  298.   top = sp ;
  299.   sp -= cnt ;
  300.   for( p = sp ; p <= top ; p++ )
  301.   {
  302.     if ( p->type < C_STRING ) cast1_to_s(p) ;
  303.     total_len += string(p)->len ;
  304.   }
  305.  
  306.   sval = new_STRING((char *)0, total_len) ;
  307.   t = sval->str ;
  308.  
  309.   /* put the pieces together */
  310.   for( p = sp ; p < top ; p++ )
  311.   { (void) memcpy(t, string(p)->str, SIZE_T(string(p)->len)) ;
  312.     (void) memcpy( t += string(p)->len, subsep_str, SIZE_T(subsep_len)) ;
  313.     t += subsep_len ;
  314.   }
  315.   /* p == top */
  316.   (void) memcpy(t, string(p)->str, SIZE_T(string(p)->len)) ;
  317.  
  318.   /* done, now cleanup */
  319.   free_STRING(string(&subsep)) ;
  320.   while ( p >= sp )  { free_STRING(string(p)) ; p-- ; }
  321.   sp->type = C_STRING ;
  322.   sp->ptr = (PTR) sval ;
  323.   return sp ;
  324. }
  325.  
  326.  
  327. /* free all memory used by an array,
  328.    only used for arrays local to a function call
  329. */
  330.  
  331. void  array_free(A)
  332.   ARRAY  A ;
  333. { register ANODE *ap ;
  334.   register D_ANODE *dp ;
  335.   register int i ;
  336.   ANODE *aq ;
  337.   D_ANODE *dq ;
  338.  
  339.   for( i = 0 ; i < A_HASH_PRIME ; i++ )
  340.   { ap = A[i].link ;
  341.     while ( ap )
  342.     { /* check its not a deleted node */
  343.       if ( ap->sval )
  344.       { free_STRING(ap->sval) ;
  345.         cell_destroy(ap->cp) ;
  346.         free_CELL(ap->cp) ;
  347.       }
  348.  
  349.       aq = ap ; ap = ap->link ;
  350.       zfree( aq, sizeof(ANODE)) ;
  351.     }
  352.  
  353.     dp = A[i].dlink ;
  354.     while ( dp )
  355.     { dq = dp ; dp = dp->dlink ; zfree(dq,sizeof(D_ANODE)) ; }
  356.   }
  357.  
  358.   zfree(A, sizeof(A[0]) * A_HASH_PRIME ) ;
  359. }
  360.